#ifndef _INPUTLAYER_H
#define _INPUTLAYER_H

// C RunTime Header Files
#include <iostream>
#include <fstream>
#include <sstream>
#include <stdlib.h> // Para malloc() etc.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <string>
#include <math.h> // Para sin(), cos() etc.
#include <vector>
#include <time.h>
#include <GL/glew.h>
#include <GL/glfw.h>

/*************************************************************************
 * Input handling definitions
 *************************************************************************/

/* Key and button state/action definitions */
#define INPUT_RELEASE              0
#define INPUT_PRESS                1
#define INPUT_PRESSED              2

/* Keyboard key definitions */
#define INPUT_KEY_UNKNOWN      -1

#define INPUT_KEY_0            0
#define INPUT_KEY_1            1
#define INPUT_KEY_2            2
#define INPUT_KEY_3            3
#define INPUT_KEY_4            4
#define INPUT_KEY_5            5
#define INPUT_KEY_6            6
#define INPUT_KEY_7            7
#define INPUT_KEY_8            8
#define INPUT_KEY_9            9

#define INPUT_KEY_Q            10
#define INPUT_KEY_W            11            
#define INPUT_KEY_E            12
#define INPUT_KEY_R            13
#define INPUT_KEY_T            14
#define INPUT_KEY_Y            15
#define INPUT_KEY_U            16
#define INPUT_KEY_I            17
#define INPUT_KEY_O            18
#define INPUT_KEY_P            19
#define INPUT_KEY_A            20
#define INPUT_KEY_S            21
#define INPUT_KEY_D            22
#define INPUT_KEY_F            23
#define INPUT_KEY_G            24
#define INPUT_KEY_H            25
#define INPUT_KEY_J            26
#define INPUT_KEY_K            27
#define INPUT_KEY_L            28
#define INPUT_KEY_Z            29
#define INPUT_KEY_X            30
#define INPUT_KEY_C            31
#define INPUT_KEY_V            32
#define INPUT_KEY_B            33
#define INPUT_KEY_N            34
#define INPUT_KEY_M            35
#define INPUT_KEY_COMA         36
#define INPUT_KEY_PUNTO        37
#define INPUT_KEY_GUION        38

#define INPUT_KEY_SPACE        39
#define INPUT_KEY_SPECIAL      40
#define INPUT_KEY_ESC          41
#define INPUT_KEY_F1           42
#define INPUT_KEY_F2           43
#define INPUT_KEY_F3           44
#define INPUT_KEY_F4           45
#define INPUT_KEY_F5           46
#define INPUT_KEY_F6           47
#define INPUT_KEY_F7           48
#define INPUT_KEY_F8           49
#define INPUT_KEY_F9           50
#define INPUT_KEY_F10          51
#define INPUT_KEY_F11          52
#define INPUT_KEY_F12          53
#define INPUT_KEY_F13          54
#define INPUT_KEY_F14          55
#define INPUT_KEY_F15          56
#define INPUT_KEY_F16          57
#define INPUT_KEY_F17          58
#define INPUT_KEY_F18          59
#define INPUT_KEY_F19          60
#define INPUT_KEY_F20          61
#define INPUT_KEY_F21          62
#define INPUT_KEY_F22          63
#define INPUT_KEY_F23          64
#define INPUT_KEY_F24          65
#define INPUT_KEY_F25          66
#define INPUT_KEY_UP           67
#define INPUT_KEY_DOWN         68
#define INPUT_KEY_LEFT         69
#define INPUT_KEY_RIGHT        70
#define INPUT_KEY_LSHIFT       71
#define INPUT_KEY_RSHIFT       72
#define INPUT_KEY_LCTRL        73
#define INPUT_KEY_RCTRL        74
#define INPUT_KEY_LALT         75
#define INPUT_KEY_RALT         76
#define INPUT_KEY_TAB          77
#define INPUT_KEY_ENTER        78
#define INPUT_KEY_BACKSPACE    79
#define INPUT_KEY_INSERT       80
#define INPUT_KEY_DEL          81
#define INPUT_KEY_PAGEUP       82
#define INPUT_KEY_PAGEDOWN     83
#define INPUT_KEY_HOME         84
#define INPUT_KEY_END          85
#define INPUT_KEY_KP_0         86
#define INPUT_KEY_KP_1         87
#define INPUT_KEY_KP_2         88
#define INPUT_KEY_KP_3         89
#define INPUT_KEY_KP_4         90
#define INPUT_KEY_KP_5         91
#define INPUT_KEY_KP_6         92
#define INPUT_KEY_KP_7         93
#define INPUT_KEY_KP_8         94
#define INPUT_KEY_KP_9         95
#define INPUT_KEY_KP_DIVIDE    96
#define INPUT_KEY_KP_MULTIPLY  97
#define INPUT_KEY_KP_SUBTRACT  98
#define INPUT_KEY_KP_ADD       99
#define INPUT_KEY_KP_DECIMAL   100
#define INPUT_KEY_KP_EQUAL     101
#define INPUT_KEY_KP_ENTER     102
#define INPUT_KEY_KP_NUM_LOCK  103
#define INPUT_KEY_CAPS_LOCK    104
#define INPUT_KEY_SCROLL_LOCK  105
#define INPUT_KEY_PAUSE        106
#define INPUT_KEY_LSUPER       107
#define INPUT_KEY_RSUPER       108
#define INPUT_KEY_MENU         109

/* Mouse button definitions */
#define INPUT_MOUSE_BUTTON_LEFT   0
#define INPUT_MOUSE_BUTTON_MIDDLE 1
#define INPUT_MOUSE_BUTTON_RIGHT  2
#define INPUT_MOUSE_BUTTON_1      3
#define INPUT_MOUSE_BUTTON_2      4
#define INPUT_MOUSE_BUTTON_3      5
#define INPUT_MOUSE_BUTTON_4      6
#define INPUT_MOUSE_BUTTON_5      7
#define INPUT_MOUSE_BUTTON_6      8
#define INPUT_MOUSE_BUTTON_7      9
#define INPUT_MOUSE_BUTTON_8      10

class cInputLayer {
    
private:
    
protected:
    cInputLayer(int setKeyboard, int setMouse);
    static cInputLayer* m_pGlobalILayer; // Puntero al Objeto Global GFX
    
public:
    
    int keyboardLenght;
    int mouseLenght;
    
    bool setKeyboard;
    bool setMouse;
    
    //Variables internas para registro de eventos
    bool boolEventMouseX;
    bool boolEventMouseY;
    bool boolEventKeyPressed;
    bool boolEventMouseButtonsPressed;
        
    int eventMouseX;
    int eventMouseY;
    
    /**
     * Posicion absoluta de X del mouse
     * @type {int}
     */
    int xPos;
	
    /**
     * Posicion absoluta de Y del mouse
     * @type {int}
     */
    int yPos;
	
    /**
     * Desplazamiento relativo de X del mouse
     * @type {int}
     */
    int xPosRelative;
	
    /**
     * Desplazamiento relativo de Y del mouse
     * @type {int}
     */
    int yPosRelative;
    
    std::vector<int> keyboard;
    std::vector<bool> eventKeyPressed;
    std::vector<bool> previousKeyboardState;
    std::vector<bool> currentKeyboardState;
    
    std::vector<int> mouse;
    std::vector<bool> eventMouseButtonsPressed;
    std::vector<bool> previousMouseButtonsState;
    std::vector<bool> currentMouseButtonsState;
    
    // Metodos publicos
    ~cInputLayer();
    
    static void Create(int setKeyboard, int setMouse);
    
    void UpdateDevices();
    void UpdateKeyboard();
    void UpdateMouse();
    
   /**
    * Informa si una tecla se encuentra presionada
    *
    * @param {int} key
    * @return {bool}
    **/
    bool keyDown(int key);

    /**
     * Informa si una tecla se dejo de presionar
     *
     * @param {int} key
     * @return {bool}
     **/
    bool keyUp(int key);

    /**
     * Informa si una tecla se presiono y luego se libero
     *
     * @param {int} key
     * @return {bool}
     **/
    bool keyPressed(int key);

    /**
     * Informa si un boton del mouse se encuentra presionado
     *
     * @param {int} button
     * @return {bool}
     **/
    bool buttonDown(int button);

    /**
     * Informa si un boton del mouse se dejo de presionar
     *
     * @param {TgcInput.MouseButtons} button
     * @return {bool}
     **/
    bool buttonUp(int button);

    /**
     * Informa si un boton del mouse se presiono y luego se libero
     *
     * @param {int} button
     * @return {bool}
     **/
    bool buttonPressed(int button);

    /** 
     * <summary>Puntero al Objeto GFX principal</summary>
     */
   static cInputLayer* GetInputLayer() {
        return m_pGlobalILayer;
    }
    
};

inline cInputLayer* InputLayer() {
    return cInputLayer::GetInputLayer();
}

#endif // _INPUTLAYER_H